Three.js 学习笔记之模型 | 您所在的位置:网站首页 › ssa模型 几何 › Three.js 学习笔记之模型 |
文章目录
模型 = 几何体 + 材质层级模型组- THREE.Group递归遍历模型树结构object3D.traverse()object3D.add (object.Object3D..) 添加对象 和 object3D.remove(object.Object3D..) 移除对象
本地(局部)坐标和世界坐标 - 基于世界坐标系的位置案例:理解本地坐标与世界坐标子对象添加坐标系THREE.AxesHelper理解对象坐标系:改变模型相对局部坐标原点位置 - 修改几何体的顶点坐标
模型隐藏或显示
模型点模型Points - 用于显示点线模型Line | LineLoop | LineSegments网格模型mesh - 三角形网格模型独有的属性与方法
几何体BufferGeometry缓冲类型几何体BufferGeometry - 基类创建几何体的方式BufferAttribute Types定义顶点法线 geometry.attributes.normal
BufferGeometry的子类几何体几何体的分段数 - 将一个大块分成几个小块SphereGeometry 球体
几何体的旋转、缩放与平移
材质 Material点材质PointsMaterial - Points使用的默认材质网格材质 Mesh纹理贴图漫反射材质MeshLambertMaterial高光网格材质 MeshPhongMaterial标准网格材质 MeshStandardMaterial物理网格材质 MeshPhysicalMaterial
![]() 关于对象坐标系我没有找到统一的名称,threeJs中文版的意思是局部空间的坐标系,本文暂时叫对象坐标系 视频讲的是局部坐标系,但我感觉这样取名容易影响对局部坐标和世界坐标的理解。会误解为局部坐标是相对于局部坐标系的坐标,但局部坐标和世界坐标都是基于世界坐标系的坐标 模型 = 几何体 + 材质模型对象的父类都是三维物体Object3D类 Three.js的材质默认正面可见、背面不可见 解决办法:材质配置对象中设置side属性 side取值描述THREE.FrontSide只有正面可见THREE.DoubleSide两面可见THREE.BackSide设置只有背面可见模型position是指模型中心的位置,是一个三维向量。几何体attributes.position是指几何体顶点位置信息,是一个BufferAttribute类型 三维物体Object3D类的属性与方法 属性与方法描述position : Vector3设置模型中心的局部坐标位置,默认值THREE.Vector3(0.0,0.0,0.0)translateX/translateY/translateZ ( distance : Float )沿着X轴将平移distance个单位,本质改变的position 值translateOnAxis ( axis : Vector3, distance : Float )沿着标准化后的向量axis(归一化后的向量表示方向)移动distancescale : Vector3各分量按参数缩放rotation:Euler(欧拉对象) 或quaternion:Quaternion(四元数)模型旋转的角度,单位是弧度rotateX(rad : Float)、rotateY(rad : Float)、rotateZ(rad : Float)绕局部空间的X/Y/Z轴旋转这个物体。本质是修改模型的角度属性.rotationrotateOnAxis ( axis : Vector3, angle : Float )绕标准化后的向量(看作轴)旋转angle个弧度clone ( recursive : Boolean ) : Object3D参数表示是否可以克隆参数的后代,默认为true克隆的规则暂时还不清楚,但克隆模型,其几何体和材质是共享的(克隆的地址)。如果几何体和材质单独调用clone克隆出来是独立的。copy ( object : Object3D, recursive : Boolean )复制参数对象到这个对象中。 事件监听器和用户定义的回调函数不会被复制。children:Array子对象数组(分组对象的子孩子),调用三维物体实例的add方法时,实际就是将参数加入到该数组中。add (object: Object3D, …)添加参数对象到这个对象的子级children,可以添加任意数量的对象。 当前传入的对象中的父级将在这里被移除,因为一个对象仅能有一个父级。name : String对象的名称,可选、不必唯一。默认值是一个空字符串。getObjectByName (name:String):Object3D从该对象开始,搜索一个对象及其子级,返回第一个带有匹配name的子对象。.getWorldPosition ( target : Vector3 ) : Vector3读取世界坐标,结果存储在参数里 const axis = new THREE.Vector3(1, 1, 1); axis.normalize(); //向量归一化后表示方向,方向不变,大小变为单位向量 //沿着axis轴表示方向平移100 mesh.translateOnAxis(axis, 100); 层级模型 组- THREE.Group语法:new THREE.Group() 说明:其父类也是三维物体Object3D,基本和三维物体Object3D一致。可以看作一个只用于分组没有实体的模型,可以分组操作模型。 作用:可以看作将模型进行分组,原来是直接将一个一个模型add进场景scene,现在是将所有模型先进行分组,然后将分组后的分组模型group添加进场景scene。 受threejs历史原因,有些时候代码中也会直接用Object3D甚至Mesh作为Group使用,可以但不推荐,语义化不够强。 group可以看作mesh1、mesh2的父对象,父对象旋转缩放平移变换,子对象跟着变化。 组对象私有的属性(无私有方法) 属性名描述isGroup:Boolean判断是否是组对象type:String不可变的值,组对象的类型Group字符串 递归遍历模型树结构object3D.traverse()语法:object3D.traverse ( callback : Function ) : undefined 本质:遍历object3D实例的children属性 每个模型可以通过object3D.name属性命名,命名之后可以通过遍历模型树搭配object3D.getObjectByName(name) ,找到具体的模型。 案例:假设有一个小区房子,结构如下 object3D.add() :将参数对象添加到对象的children中,传入的对象本身就有父级的话将在这里被移除,因为一个对象仅能有一个父级。 object3D.remove():从当前对象的children中移除对象,可以移除任意数量的对象。 本地(局部)坐标和世界坐标 - 基于世界坐标系的位置这里的本地和世界是相对于有无父元素来说,坐标都是基于世界坐标系的位置 任何一个模型的本地坐标(局部坐标)就是模型的.position属性。一个模型的世界坐标,模型自身.position和所有父对象.position累加的坐标。1.改变子对象的.position,子对象在3D空间中的坐标会发生改变。 2.改变父对象的.position,子对象在3D空间中的位置也会跟着变化,也就是说父对象.position和子对象.position叠加才是才是子对象的.position。 object.getWorldPosition(Vector3) 获取世界坐标 语法:object.getWorldPosition(Vector3) 描述:读取一个模型的世界坐标,并把读取结果存储到参数Vector3中。 案例:理解本地坐标与世界坐标案例1:可以看见局部坐标变了,但对象坐标系位置是没有变化的。如果将对象坐标系称为局部坐标系,会误解为局部坐标是相对于局部坐标系的坐标。 const axesHelper = new THREE.AxesHelper(60); const mesh = new THREE.Mesh(geometry, material); mesh.add(axesHelper); mesh.position.set(25,25,25) scene.add(mesh); const axesHelper1 = new THREE.AxesHelper(150);// 世界坐标系 scene.add(axesHelper1); console.log("世界坐标",mesh.getWorldPosition(new THREE.Vector3())); console.log("本地坐标",mesh.position);
语法:AxesHelper( size : Number ) 参数:size (可选) 表示代表轴的线段长度.,默认为 1。 说明:红色(R)代表 X 轴. 绿色(G)代表 Y 轴. 蓝色(B)代表 Z 轴。 继承链:Object3D → Line → LineSegments mesh.add(坐标系)给mesh添加一个对象坐标系 //可视化mesh的局部坐标系 const meshAxesHelper = new THREE.AxesHelper(50); mesh.add(meshAxesHelper);在场景scene添加世界坐标系 const axesHelper = new THREE.AxesHelper( 5 ); scene.add( axesHelper ); 理解对象坐标系:改变模型相对局部坐标原点位置 - 修改几何体的顶点坐标平移几何体,改变几何体的顶点坐标,可以发现世界坐标和局部坐标没有变化,但对象坐标系不在几何体中心了。所以对象坐标系只是针对几何体对象 const axesHelper = new THREE.AxesHelper(60); const mesh = new THREE.Mesh(geometry, material); geometry.translate(25,25,25); mesh.add(axesHelper); mesh.position.set(25,25,25) const group = new THREE.Group(); group.add(mesh); scene.add(group); group.position.set(25,25,25) const axesHelper1 = new THREE.AxesHelper(150);// 世界坐标系 scene.add(axesHelper1); console.log("世界坐标",mesh.getWorldPosition(new THREE.Vector3())); console.log("本地坐标",mesh.position);方式1:隐藏网格模型object3D.visible : Boolean mesh.visible =false;// 隐藏一个网格模型,visible的默认值是true group.visible =false;// 隐藏一个包含多个模型的组对象group方式2:隐藏材质Material.visible:Boolean ,通过该属性可以控制是否隐藏使用了该材质的模型对象。 mesh.material.visible =false; 模型 点模型Points - 用于显示点语法:new Points( geometry : BufferGeometry, material : Material ) geometry 几何体对象(可选),BufferGeometry的实例,默认值是一个新的BufferGeometry。material 材质对象(可选),默认值为PointsMaterial。描述:一个用于显示点的类,将几何体geometry渲染成点。 线模型Line | LineLoop | LineSegments语法:new Line( geometry : BufferGeometry, material : Material ) geometry 线段的顶点,默认值是一个新的BufferGeometry。material 线的材质,默认值是一个新的且随机颜色的LineBasicMaterial。 线模型绘制线条的规则Line从第一个点开始到最后一个点,依次连成线不闭合LineLoop从第一个点开始到最后一个点,依次连成线,并将最后一个顶点连回第一个顶点 闭合LineSegments从第一个点开始,第一个点连接第二个点,第三个点连接第四个点…有n个点,就有n/2条线 间断 网格模型mesh - 三角形本质:一个一个三角形拼接 说明:几何体所有顶点坐标三个为一组,构成一个三角形,多组顶点构成多个三角形,用来模拟物体的表面。 常见几何体可以看成是封装后的BufferGeometry 缓冲类型几何体BufferGeometry - 基类描述:BufferGeometry是一个没有任何形状的空几何体,通过定义顶点数据将BufferGeometry自定义为任何几何形状。每个几何体可以看作是由多个顶点构成的图案。 BufferGeometry实例的属性与方法 属性名/方法描述index:BufferAttribute绑定几何体的顶点索引,每个三角形都绑定了三个顶点的索引。 允许顶点坐标在三角形中复用。attributes : Object存储该几何体相关属性的hashmap (这里直接打印看不见里面的属性),每个value的类型都是BufferAttribute可以通过 几何体.setAttribute 和 几何体.getAttribute 添加和访问与当前几何体相关的属性。案例 1.使用 THREE.BufferGeometry创建一个空的几何体对象 const geometry = new THREE.BufferGeometry();2.利用Float32Array定义顶点数据,使用属性缓冲区对象BufferAttribute表示threejs几何体顶点数据。 通过javascript类型化数组Float32Array创建一组xyz坐标数据用来表示几何体的顶点坐标。 //类型化数组创建顶点数据 const vertices = new Float32Array([ 0, 0, 0, //顶点1坐标 50, 0, 0, //顶点2坐标 0, 100, 0, //顶点3坐标 0, 0, 10, //顶点4坐标 0, 0, 100, //顶点5坐标 50, 0, 10, //顶点6坐标 ]); // 创建属性缓冲区对象,3个为一组,表示一个顶点的xyz坐标 const attribue = new THREE.BufferAttribute(vertices, 3);3.设置几何体的定点.attributes.position // 设置几何体attributes属性的位置属性 geometry.attributes.position = attribue;4.渲染顶点 4.1使用点模型渲染顶点数据,会把几何体渲染为点,网格模型Mesh会把几何体渲染为面。 // 点渲染模式 const material = new THREE.PointsMaterial({ color: 0xffff00, size: 10.0 //点对象像素尺寸 }); const points = new THREE.Points(geometry, material); //点模型对象4.2使用线模型渲染顶点数据,从第一个点开始到最后一个点,依次连成线。 // 线材质对象 const material = new THREE.LineBasicMaterial({ color: 0xff0000 //线条颜色 }); // 创建线模型对象 const line = new THREE.Line(geometry, material);
案例: 构建一个矩形平面几何体 - 通过顶点数据 顶点坐标:一个矩形平面,可以至少通过两个三角形拼接而成。 三角形方向:两个三角形的正面需要保持一致 几何体顶点索引数据 - 通过顶点索引 在上述案例中,坐标4和坐标5其实是重复的坐标,重复的坐标可以复用吗? // 删除重复的坐标 const vertices = new Float32Array([ 0, 0, 0, //顶点1坐标 | 索引0 80, 0, 0, //顶点2坐标 4坐标 | 索引1 80, 80, 0, //顶点3坐标 5坐标 | 索引2 0, 80, 0, //顶点6坐标 | 索引3 ]); // Uint16Array类型数组创建顶点索引数据 const indexs = new Uint16Array([ // 下面索引值对应顶点位置数据中的顶点坐标 0, 1, 2, 0, 2, 3, ]) // 索引数据赋值给几何体的index属性 1个为1组 geometry.index = new THREE.BufferAttribute(indexs, 1); BufferAttribute Types在 three.js 中一共有 9 种 BufferAttribute,每种和 JavaScript 中的类型相对应Typed Arrays。使用new创建BufferAttribute对象时,传入数组是什么内省,生成的BufferAttribute就是什么类型 BufferAttribute 类型对应的JS数组类型THREE.Float64BufferAttributeFloat64ArrayTHREE.Uint32BufferAttributeUint32ArrayTHREE.Int32BufferAttributeInt32ArrayTHREE.Uint16BufferAttributeUint16ArrayTHREE.Int16BufferAttributeInt16ArrayTHREE.Uint8ClampedBufferAttributeUint8ClampedArrayTHREE.Uint8BufferAttributeUint8ArrayTHREE.Int8BufferAttributeInt8Array 定义顶点法线 geometry.attributes.normal数学上法线的概念 一个平面,法线的就是改平面的垂线,如果是光滑曲面,一点的法线就是该点切面的法线。 Three.js中法线是通过顶点定义,默认情况下,每个顶点都有一个法线数据。 无顶点索引的使用方式 const vertices = new Float32Array([ 0, 0, 0, //顶点1坐标 80, 0, 0, //顶点2坐标 80, 80, 0, //顶点3坐标 0, 0, 0, //顶点4坐标 80, 80, 0, //顶点5坐标 0, 80, 0, //顶点6坐标 ]); geometry.attributes.position =new THREE.BufferAttribute(vertices, 3); const material = new THREE.MeshLambertMaterial({ color: 0xff0000, //线条颜色 side: THREE.DoubleSide }); // 矩形平面,无索引,两个三角形,6个顶点 // 每个顶点的法线数据和顶点位置数据一一对应 const normals = new Float32Array([ 0, 0, 1, //顶点1法线( 法向量 ) 0, 0, 1, //顶点2法线 0, 0, 1, //顶点3法线 0, 0, 1, //顶点4法线 0, 0, 1, //顶点5法线 0, 0, 1, //顶点6法线 ]); // 设置几何体的顶点法线属性.attributes.normal geometry.attributes.normal = new THREE.BufferAttribute(normals, 3);有顶点索引的使用方式 const vertices = new Float32Array([ 0, 0, 0, //顶点1坐标 顶点4坐标 80, 0, 0, //顶点2坐标 80, 80, 0, //顶点3坐标 顶点5坐标 0, 80, 0, //顶点6坐标 ]); geometry.attributes.position =new THREE.BufferAttribute(vertices, 3); // 矩形平面,有索引,两个三角形,有2个顶点重合,有4个顶点 // Uint16Array类型数组创建顶点索引数据 const indexs = new Uint16Array([ // 下面索引值对应顶点位置数据中的顶点坐标 0, 1, 2, 0, 2, 3, ]) geometry.index = new THREE.BufferAttribute(indexs, 1); // 每个顶点的法线数据和顶点位置数据一一对应 const normals = new Float32Array([ 0, 0, 1, //顶点1法线( 法向量 ) 0, 0, 1, //顶点2法线 0, 0, 1, //顶点3法线 0, 0, 1, //顶点4法线 ]); // 设置几何体的顶点法线属性.attributes.normal geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); BufferGeometry的子类几何体很多几何体构造函数提供了分段数,其默认值为1。除去必要参数之外的第一个参数表示x轴分成几段,第二个参数表示y轴分成几段。 PlaneGeometry矩形平面案例 // 把一个矩形x轴方向分为两段,每份2个三角形,一共4个三角形 const geometry = new THREE.PlaneGeometry(50,50,2,1);
语法:new SphereGeometry(radius : Float,可选参数) 由于所有几何体都是由一个一个三角形组成,所以如果球体细分数比较低,表面就不会那么光滑,分段数越大越接近一个球。 可选参数描述widthSegments水平分段数(沿着经线分段),最小值为3,默认值为32。heightSegments垂直分段数(沿着纬线分段),最小值为2,默认值为16。 几何体的旋转、缩放与平移 材质 Material材质Material是所有材质的父类。 创建材质:new 材质(配置对象) 说明:材质描述了物体的外观,定义方式与渲染器无关 配置对象里可配置的属性其实就是返回的材质实例拥有的属性 /* 案例 */ const material = new THREE.MeshLambertMaterial({ color:0xff0000, wireframe:true, }); console.log("material.wireframe:",material.wireframe) 方法与属性描述transparent : Boolean定义此材质是否透明,默认为false。对渲染有影响,透明对象需要特殊处理,并在非透明对象之后渲染。设置为true之后可以使用opacity调整透明度。opacity:Float范围是0.0 - 1.0,表明材质的透明度。值0.0表示完全透明,1.0表示完全不透明(默认)。如果transparent属性未设置为true,则材质将保持完全不透明,此值仅影响其颜色。side:Integer定义将要渲染哪一面,默认是正面(相机照着那面,连接的顺序是逆时针) 点材质PointsMaterial - Points使用的默认材质语法:new PointsMaterial( parameters : Object ) 实例的属性和方法 属性/方法描述size:Number设置点的大小,默认值为1.0。color:Color材质的颜色,默认值为白色 (0xffffff)。 网格材质 Mesh使用收光照影响的材质时,如果没有光照默认是黑色的(renderer画布设置了颜色可以看出) 材质描述受光照影响特点MeshBasicMaterial基础光照模型×MeshLambertMaterialLambert光照模型(漫反射)√MeshPhongMaterialPhong光照模型(漫反射、高光反射)√MeshStandardMaterial基于物理的光照模型(PBR物理材质),可以提供更加真实的材质效果√物理网格材质使用了更复杂的着色器功能,大部分的特性是默认关闭的,需要手动开启。MeshPhysicalMaterial属于PBR物理材质(基于物理的渲染physically-based rendering),可以提供更加真实的材质效果√MeshPhysicalMaterial是MeshStandardMaterial的扩展子类渲染占用资源和表现能力 整体上来看,就是渲染表现能力越强,占用的计算机硬件资源更多。 占用渲染资源 MeshBasicMaterial < MeshLambertMaterial < MeshPhongMaterial < MeshStandardMaterial < MeshPhysicalMaterial渲染表现能力 MeshBasicMaterial < MeshLambertMaterial < MeshPhongMaterial < MeshStandardMaterial < MeshPhysicalMaterial 纹理贴图纹理贴图学习笔记 漫反射材质MeshLambertMaterial语法:new MeshLambertMaterial( parameters : Object ) 对光照的反射为漫反射:光线向四周反射。 Lambert网格材质的属性与方法 属性和方法描述wireframe : Boolean将几何体渲染为线框,默认值为false,渲染为平面多边形。 高光网格材质 MeshPhongMaterial语法:new MeshPhongMaterial( parameters : Object ) 参数对象的属性 = 自有属性 + Material基类继承的属性 对光照的反射为镜面反射:想象一面镜子的反射,如果刚好反射光对眼睛,会非常刺眼(某个局部区域高亮,像擦了高光) 注意:AmbientLight环境光没有方向,整体改变场景的光照。所以只有环境光的,高光效果会失效。 MeshPhongMaterial高光网格材质配置参数的自有属性 属性名属性描述color : Color材质的颜色,默认值为白色(0xffffff)shininess高亮的程度,越高的值越闪亮,默认30specular高光颜色,默认为0x111111灰色 标准网格材质 MeshStandardMaterialPBR材质金属渲染效果 - 金属度metalness和粗糙度roughness 属性名属性值描述.metalness : Float材质与金属的相似度。非金属材质,如木材或石材,使用0.0,金属使用1.0,通常没有中间值。 0.0到1.0之间的值可用于生锈金属的外观(默认0.0)。如果还提供了metalnessMap,则两个值相乘。.roughness : Float材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射(默认1.0)。如果还提供roughnessMap,则两个值相乘。生活中不同物体表面的粗糙程度不同,比如地面比较粗糙,比如镜子表面就非常非常光滑。越光滑镜面反射能力越强,越粗糙,表面镜面反射能力越弱 物理网格材质 MeshPhysicalMaterial清漆层Clearcoat Clearcoat类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。 属性名属性值描述清漆层属性clearcoat:Float0(默认值)-1表示clear coat层的强度(图层厚度),模拟物体表面一层透明图层,就好比你在物体表面刷了一层透明清漆。清漆层粗糙度clearcoatRoughness : Float由0.0(默认)到1.0。 默认为0.0clear coat层的粗糙度 |
CopyRight 2018-2019 实验室设备网 版权所有 |